package com.dapeng.jackson.serializer;

import cn.dapeng.common.StringTools;
import com.dapeng.jackson.abstracts.BaseJKAnnotationDeSerializer;
import com.dapeng.jackson.abstracts.BaseJKEnumKey;
import com.dapeng.jackson.annotations.JKEnumDeserializer;
import com.dapeng.jackson.enums.JKEnumMode;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JavaType;
import org.springframework.util.ReflectionUtils;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

/**
 * @BelongProject study
 * @BelongPackage com.dapeng.jackson.serializer
 * @Description TODO
 * @ClassName JKEnumFormatDeserializer
 * @Author xupenghong
 * @Date 2024/9/13 16:24
 * @Version 1.0.0
 */
public class JKEnumFormatDeserializer extends BaseJKAnnotationDeSerializer<JKEnumDeserializer, Object> {

    private Class<Enum<?>> listEnumClass;

    /**
     * 只有当字段类型为枚举类或者枚举List的时候才使用此反序列化器
     */
    @Override
    protected boolean isFilterDeserializer(BeanProperty property) {
        if (Enum.class.isAssignableFrom(fieldClass)) {
            return true;
        }

        if (List.class.isAssignableFrom(fieldClass)) {
            //  获取泛型参数
            JavaType type = property.getType();
            Class<?> rawClass = type.getContentType().getRawClass();
            if (Enum.class.isAssignableFrom(rawClass)) {
                listEnumClass = (Class<Enum<?>>) rawClass;
                return true;
            } else {
                return false;
            }

        }
        return false;
    }

    @Override
    public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        if (!StringTools.isNoneEmpty(p.getText())) {
            return null;
        }

        if (Enum.class.isAssignableFrom(fieldClass)) {
            String enumValue = p.getText();
            Class<?> enumClass = this.fieldClass;
            Enum<?> result = getEnumValue(enumValue, enumClass);

            if (!this.annotation.nullable() && result == null) {
                throw new IllegalArgumentException("从参数 【" + enumValue + "】无法反序列化成字段【" + fieldClass.getSimpleName() + " " + fieldName + "】,请重新传参");
            }
            return result;
        }

        if (List.class.isAssignableFrom(fieldClass)) {
            TreeNode treeNode = p.getCodec().readTree(p);
            String s = treeNode.toString();
            s = StringTools.replaceChars(s, "\"", "");
            List<String> strings = Arrays.asList(StringTools.toArray(s, "[", "]", ","));
            List<Enum<?>> valueList = new ArrayList<>();
            for (String element : strings) {
                valueList.add(getEnumValue(element, listEnumClass));
            }
            return valueList;
        }

        return null;
    }

    private Enum<?> getEnumValue(String enumValue, Class<?> enumClass) {
        JKEnumMode mode = this.annotation.mode();
        Enum<?> result;
        if (mode.equals(JKEnumMode.FIELD)) {
            result = getEnumForCustomField(enumValue, enumClass);
        } else if (mode.equals(JKEnumMode.TO_STRING)) {
            result = getEnumForToString(enumValue, enumClass);
        } else if (mode.equals(JKEnumMode.BASE_ENUM_KEY0)) {
            result = getEnumForBasEnumKey(enumValue, enumClass, e -> e.getEnumVey0() == null ? null : e.getEnumVey0().toString());
        } else if (mode.equals(JKEnumMode.BASE_ENUM_KEY1)) {
            result = getEnumForBasEnumKey(enumValue, enumClass, e -> e.getEnumVey1() == null ? null : e.getEnumVey1().toString());
        } else {
            result = getEnum(enumValue, enumClass);
        }
        return result;
    }

    private Enum<?> getEnumForBasEnumKey(String enumValue, Class<?> enumClass, Function<BaseJKEnumKey, String> getEnum) {
        if (!BaseJKEnumKey.class.isAssignableFrom(enumClass)) {
            throw new IllegalArgumentException("对于枚举类" + enumClass.getSimpleName() + "当指定为根据自定义枚举key序列时，请实现BaseJKEnumKey接口");
        }
        return findEnumConstant(enumValue, enumClass, e -> getEnum.apply(((BaseJKEnumKey) e)));
    }

    private Enum<?> getEnumForToString(String enumValue, Class<?> enumClass) {
        return findEnumConstant(enumValue, enumClass, Enum::toString);
    }

    public Enum<?> findEnumConstant(String enumValue, Class<?> enumClass, Function<Enum<?>, String> getEnum) {
        Enum<?> result = null;
        Enum<?>[] enumConstants = (Enum<?>[]) enumClass.getEnumConstants();
        for (Enum<?> tmp : enumConstants) {
            String value = getEnum.apply(tmp);
            if (enumValue.equals(value)) {
                result = tmp;
                break;
            }
        }
        return result;
    }

    private Enum<?> getEnumForCustomField(String enumValue, Class<?> enumClass) {
        String fieldName = annotation.fieldName();
        // 获取枚举类的字段值
        Field field = ReflectionUtils.findField(enumClass, fieldName);
        if (field == null) {
            throw new IllegalArgumentException(enumClass.getSimpleName() + "枚举类中不存在该字段" + fieldName);
        }
        field.setAccessible(true);
        return findEnumConstant(enumValue, enumClass, e -> {
            Object filedValue = ReflectionUtils.getField(field, e);
            return filedValue == null ? null : filedValue.toString();
        });
    }

    public Enum<?> getEnum(String enumValue, Class<?> enumClass) {
        return findEnumConstant(enumValue, enumClass, Enum::name);
    }
}